<?php

/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------
|
| The first thing we will do is create a new Laravel application instance
| which serves as the "glue" for all the components of Laravel, and is
| the IoC container for the system binding all of the various parts.
|
*/
// 创建一个应用，这个启动文件也可以看作是一个服务提供者，不过他并没有boot，register方法。
// 因为入口文件直接加载它，所有这些没必要的方法就不存在了。

// 创建Application实例，可以通过$_ENV全局变量重置APP所在目录
$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
// 实例化完成以下事情：
// 一、bindPathsInContainer(); // 绑定应用程序中各种路径。（此时整个laravel的各个目录就以基础目录是准，相对固定了）。
//$this->instance('path', $this->path());
//$this->instance('path.base', $this->basePath());
//$this->instance('path.lang', $this->langPath());
//$this->instance('path.config', $this->configPath());
//$this->instance('path.public', $this->publicPath());
//$this->instance('path.storage', $this->storagePath());
//$this->instance('path.database', $this->databasePath());
//$this->instance('path.resources', $this->resourcePath());
//$this->instance('path.bootstrap', $this->bootstrapPath());
// 二、$this->registerBaseBindings(); // 将最基本的app注册到了容器，并且，如果有软件包（组件）缓存时，则直接绑定导入的缓存。
// 三、$this->registerBaseServiceProviders(); // 注册框架运行必备的系统组服务提供者（providers），
//包括：事件（events），日志（log），路由相关服务（router、url、redirector、psrRquest、psrResponse、controllerDespatcher这个完成了MVC的控制器分发）。
// 分别调用了EventServiceProvider、LogServiceProvider、RoutingServiceProvider并调用了对应服务提供者的bootstap()方法！、、、、
// 四、$this->registerCoreContainerAliases(); // 将系统必要核心组件，别名化处理，从此以后，所有的Laravel系统级组件都可以通过另外调用。

// 方法说明：
// instance()注册已经存在的对象到共享容器。
// singleton()注册一个共享类到容器，后期需要make()实例化。

// App是如何注册服务提供者（Provider）的并执行它的 bootstrap() 方法？
// 比如：$app->register(new EventServiceProvider($app));
// 首先调用 provider的register() 方法。
// 接着，如果 provider 有 bindings 属性时，则对应将 bindings 的数组类或对象 bind() 非共享到容器中。（批量注入）
// 接着，如果 provider 有 singletons 属性时，则对应将 singletons 的数组或对象 singleton() 共享到容器。（批量注入）
// 最后，如果框架 app 支持 boot，那么会检查provider对象是否包含 boot() 方法，如果有则最后调用。（注意，这里的 boot() 方法是否必须调用是可配置的，而且它必须是在 register() 调用的最后执行，有这么个确定时间差。）
// 小节：服务提供者，在整个框架生命周期中，起到一个决定性的





/*
|--------------------------------------------------------------------------
| Bind Important Interfaces
|--------------------------------------------------------------------------
|
| Next, we need to bind some important interfaces into the container so
| we will be able to resolve them when needed. The kernels serve the
| incoming requests to this application from both the web and CLI.
|
*/

// 绑定单例Http Web处理内核
// 将 Kernel 注册到容器，此时以下 Kernel 并未作实例化
// laravel 中亮眼的点: 绑定是按照 Illuminate\Contracts\Xxx -> App\xxx 的约束来实现, 全局统一，是个通用规则。即框架定义规则，开发人员按照规则来实现。
// 此约束就连 \Illuminate\Contracts\Foundation\Application => \Illuminate\Foundation\Application 都适用!
$app->singleton(
    Illuminate\Contracts\Http\Kernel::class,
    App\Http\Kernel::class
);

// 绑定单例Command命令行处理内核（这个在web实例下是不会被使用的，只有在 artisan 下才会被使用，因为 index 代表 web 应用入口，artisan 代表 command 应用入口）
// 而 path/bootstrap/app.php 被公共调用。
$app->singleton(
    Illuminate\Contracts\Console\Kernel::class, // 代码规范
    App\Console\Kernel::class // 具体实现
);

// 绑定单例Exception异常处理器
$app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    App\Exceptions\Handler::class
);
// 以上三个仅仅是注入到容器，并没有实例化，后续按照需要会通过 make() 来解析并实例化。

/*
|--------------------------------------------------------------------------
| Return The Application
|--------------------------------------------------------------------------
|
| This script returns the application instance. The instance is given to
| the calling script so we can separate the building of the instances
| from the actual running of the application and sending responses.
|
*/

return $app;
